package jchess;

/*
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.util.ArrayList;
import java.util.Iterator;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.util.List;
import javax.swing.ImageIcon;

/**
Class to represent a piece (any kind) - this class should be extended to represent pawn, bishop etc.
 */
public abstract class Piece implements Comparable<Piece> {

    Chessboard chessboard; // <-- this relations isn't in class diagram, but it's necessary :/
    public Square square;
    public Player player;
    protected String name;
    protected String symbol;
    protected static Image imageBlack;// = null;
    protected static Image imageWhite;// = null;
    public Image orgImage;
    public Image image;
    public static short value = 0;

    Piece(Chessboard chessboard, Player player) {
        this.chessboard = chessboard;
        this.player = player;
        if (player.color == player.color.black) {
            image = imageBlack;
        } else {
            image = imageWhite;
        }
        this.name = this.getClass().getSimpleName();
        this.symbol = this.name.substring(0, 1);
    }
    /* Method to draw piece on chessboard
     * @graph : where to draw
     */

    final void draw(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        Point topLeft = this.chessboard.getTopLeftPoint();
        float height = this.chessboard.get_square_height();
        int int_height = (int) height;
        Point pt = this.chessboard.getSquareTopLeft(this.square);
        int x = pt.x;
        int y = pt.y;
        float addX = (height - image.getWidth(null)) / 2;
        float addY = (height - image.getHeight(null)) / 2;
        if (image != null && g != null) {
            Image tempImage = orgImage;
            BufferedImage resized = new BufferedImage(int_height, int_height, BufferedImage.TYPE_INT_ARGB_PRE);
            Graphics2D imageGr = (Graphics2D) resized.createGraphics();
            imageGr.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            imageGr.drawImage(tempImage, (int) (0 + addX), (int) (0 + addY), int_height, int_height, null);
            imageGr.dispose();
            image = resized.getScaledInstance(int_height, int_height, 0);
            g2d.drawImage(image, (int) (x + addX), (int) (y + addY), null);
        } else {
            System.out.println("image is null!");
        }
    }

    void clean() {
    }

    /** method check if Piece can move to given square
     * @param square square where piece want to move (Square object)
     * @param allmoves  all moves which can piece do
     * */
    boolean canMove(Square square, ArrayList allmoves) {
        //throw new UnsupportedOperationException("Not supported yet.");
        ArrayList moves = allmoves;
        for (Iterator it = moves.iterator(); it.hasNext();) {
            Square sq = (Square) it.next();//get next from iterator
            if (sq == square) {//if adress is the same
                return true; //piece canMove
            }
        }
        return false;//if not, piece cannot move
    }

    void setImage() {
        if (this.player.color == this.player.color.black) {
            image = imageBlack;
        } else {
            image = imageWhite;
        }
    }
    //void setImages(String white, String black) {
        /* method set image to black or white (depends on player color)
     * @white: String with name of image with white piece
     * @black: String with name of image with black piece
     * */
    //    this.imageBlack = black;
    //     this.imageWhite = white;
    //     if(player.color == player.color.black) {
    //         this.image = GUI.loadImage(imageBlack);
    //     } else {
    //          this.image = GUI.loadImage(imageWhite);
    //     }
    //  }/*--endOf-setImages(String white, String black)--*/

    abstract public ArrayList allMoves();

    /** Method is useful for out of bounds protection
     * @param x  x position on chessboard
     * @param y y position on chessboard
     * @return true if parameters are out of bounds (array)
     * */
    protected boolean isout(int x, int y) {
        if (x < 0 || x > 7 || y < 0 || y > 7) {
            return true;
        }
        return false;
    }

    /** 
     * @param x y position on chessboard
     * @param y  y position on chessboard
     * @return true if can move, false otherwise
     * */
    protected boolean checkPiece(int x, int y) {
        Piece piece = chessboard.squares[x][y].getPiece();
        if (King.analisandoCasasNeutras == true && chessboard.squares[x][y].getPiece() != null
                && chessboard.squares[x][y].getPiece().getName().equals("King") && piece.player != this.player) {
            return true;
        }
        if (chessboard.squares[x][y].getPiece() != null
                && chessboard.squares[x][y].getPiece().getName().equals("King")) {
            return false;
        }
        if (piece == null || //if this sqhuare is empty
                piece.player != this.player) //or piece is another player
        {
            return true;
        }
        return false;
    }

    /** Method check if piece has other owner than calling piece
     * @param x x position on chessboard
     * @param y y position on chessboard
     * @return true if owner(player) is different
     * */
    protected boolean otherOwner(int x, int y) {
        Square sq = chessboard.squares[x][y];
        if (sq.getPiece() == null) {
            return false;
        }
        if (this.player != sq.getPiece().player) {
            return true;
        }
        return false;
    }

    public String getSymbol() {
        return this.symbol;
    }

    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    abstract public int getValor();

    abstract public Image getImage();

    abstract public ImageIcon getImageIcon();

    @Override
    public String toString() {
        return name;
    }

    @Override
    public int compareTo(Piece outraPeca) {
        return outraPeca.getValor() - this.getValor();
    }

    public boolean temOutraDeMesmoTipoECorNaColuna(Square casaOrigem) {
        int linhaOrigem = casaOrigem.getPozY();
        int colunaOrigem = casaOrigem.getPozX();
        boolean tem = false;
        // percorre a coluna, linha a linha
        for (int linha = 0; linha < 8; linha++) {
            if (linha == linhaOrigem) {
                continue;
            }
            Piece pecaEncontrada = this.chessboard.squares[colunaOrigem][linha].getPiece();
            if (pecaEncontrada != null
                    && pecaEncontrada.mesmoTipo(this)
                    && pecaEncontrada.mesmaCor(this)) {
                tem = true;
                break;
            }
        }

        return tem;
    }

    public boolean temOutraDeMesmoTipoECorNaLinha(Square casaOrigem) {
        int linhaOrigem = casaOrigem.getPozY();
        int colunaOrigem = casaOrigem.getPozX();
        boolean tem = false;
        // percorre a linha, coluna a coluna
        for (int coluna = 0; coluna < 8; coluna++) {
            if (coluna == colunaOrigem) {
                continue;
            }
            Piece pecaEncontrada = this.chessboard.squares[coluna][linhaOrigem].getPiece();
            if (pecaEncontrada != null
                    && pecaEncontrada.mesmoTipo(this)
                    && pecaEncontrada.mesmaCor(this)) {
                tem = true;
                break;
            }
        }

        return tem;
    }

    /*
     * se a lista de retorno estiver:
     * - vazia: pode colocar só a casa de destino normalmente
     * - com 1: pega a coluna de origem, ou a linha
     * - com 2 ou mais: pega ambos
     */
    public List<Piece> outrasQuePodemIrParaAMesmaCasa(Square casaDestino) {
        List<Piece> retorno = new ArrayList<Piece>();

        Piece pecaSalva = null;
        int i;
        Square squareAux = null;

        for (int linha = 0; linha < 8; linha++) {
            for (int coluna = 0; coluna < 8; coluna++) {
                Piece pecaEncontrada = this.chessboard.squares[coluna][linha].getPiece();

                if (pecaEncontrada != null
                        && pecaEncontrada.mesmoTipo(this)
                        && pecaEncontrada.mesmaCor(this)
                        && !pecaEncontrada.square.equals(casaDestino)) {

                    //Salvo a peca do tabuleiro
                    pecaSalva = null;
                    pecaSalva = this.chessboard.squares[casaDestino.getPozX()][casaDestino.getPozY()].getPiece();

                    //Tirou a peca do tabuleiro
                    this.chessboard.squares[casaDestino.getPozX()][casaDestino.getPozY()].piece = null;

                    if (pecaEncontrada.allMoves().contains(casaDestino)) {
                        //Tem ambiguidade
                        retorno.add(pecaEncontrada);
                    }
                    //Retorna a peca no tabuleiro
                    this.chessboard.squares[casaDestino.getPozX()][casaDestino.getPozY()].piece = pecaSalva;
                }
            }
        }

        return retorno;
    }

    public boolean mesmoTipo(Piece outraPeca) {
        return this.getName().equals(outraPeca.getName());
    }

    public boolean mesmaCor(Piece outraPeca) {
        return this.player.color == outraPeca.player.color;
    }
}
